#include "os_timer.h"

#define TIMER_LIST_SIZE     10

typedef struct os_timer
{
  os_time_t interval;
  os_time_t start_time;
  os_timer_func_t func;
  void *param;
  uint8 flags;
}timer_list_item_t;

typedef struct timer_list
{
  mlist_t list;
  uint8 used[TIMER_LIST_SIZE];
  timer_list_item_t items[TIMER_LIST_SIZE];
}timer_list_t;

static volatile os_time_t g_nettime;
static volatile os_time_t g_systime;
static timer_list_t g_timer_list;

static uint8 _timer_list_foreach(void *item, mlist_list_size_t index)
{
  uint8 i_state;
  timer_list_item_t *timer = (timer_list_item_t *)item;

  if(timer->flags & OS_TIMER_FLAG_IMME)
  {
    timer->flags &= ~OS_TIMER_FLAG_IMME;
    goto execute;
  }

  if(OS_SYSTIME_BEYOND_SPAN(timer->start_time, timer->interval))
  {
    goto execute;
  }

  return 0;
execute:
  timer->func(timer->param);
  OS_ENTER_CRITICAL(i_state);
  timer->start_time = os_timer_get_systime();
  OS_EXIT_CRITICAL(i_state);
  if(!(timer->flags & OS_TIMER_FLAG_REPEAT))
  {
    OS_ENTER_CRITICAL(i_state);
    mlist_del(&g_timer_list.list, index);
    OS_EXIT_CRITICAL(i_state);
  }

  return 1;
}

void os_timer_init()
{
  mlist_init(&g_timer_list.list, g_timer_list.used, g_timer_list.items, TIMER_LIST_SIZE, sizeof(timer_list_item_t));
}

void os_timer_poll()
{
  mlist_foreach(&g_timer_list.list, _timer_list_foreach);
}

os_timer_t os_timer_set(os_timer_func_t func, os_time_t interval, void *param, uint8 flags)
{
  uint8 i_state;
  mlist_list_size_t index;
  timer_list_item_t *timer;
  OS_ENTER_CRITICAL(i_state);
  index = mlist_add(&g_timer_list.list, NULL, 0);
  if(index < 0)
  {
    //os_log("timer list is full.");
    goto ret;
  }

  timer = mlist_get(&g_timer_list.list, index);
  timer->func = func;
  timer->interval = interval;
  timer->flags = flags;
  timer->param = param;
  timer->start_time = os_timer_get_systime();

ret:
  OS_EXIT_CRITICAL(i_state);
  return index;
}

uint8 os_timer_is_valid(os_timer_t timer)
{
  return (mlist_get(&g_timer_list.list, timer) != NULL);
}

void os_timer_reset(os_timer_t timer)
{
  timer_list_item_t *timer_item;
  timer_item = mlist_get(&g_timer_list.list, timer);
  if(timer_item)
  {
    timer_item->start_time = os_timer_get_systime();
  }
}

void os_timer_del(os_timer_t timer)
{
  uint8 i_state;
  OS_ENTER_CRITICAL(i_state);
  mlist_del(&g_timer_list.list, timer);
  OS_EXIT_CRITICAL(i_state);
}

void os_timer_pass_ms()
{
  g_systime++;
  g_nettime++;
}

os_time_t os_timer_get_systime()
{
  uint8 i_state;
  os_time_t ret;

  OS_ENTER_CRITICAL(i_state);
  ret = g_systime;
  OS_EXIT_CRITICAL(i_state);
  return ret;
}

os_time_t os_timer_get_nettime()
{
  uint8 i_state;
  os_time_t ret;

  OS_ENTER_CRITICAL(i_state);
  ret = g_nettime;
  OS_EXIT_CRITICAL(i_state);
  return ret;
}

void os_timer_add_systime(os_time_t time)
{
  uint8 i_state;
  OS_ENTER_CRITICAL(i_state);
  g_systime += time;
  g_nettime += time;
  OS_EXIT_CRITICAL(i_state);
}

void os_timer_set_nettime(os_time_t time)
{
  uint8 i_state;
  OS_ENTER_CRITICAL(i_state);
  g_nettime = time;
  OS_EXIT_CRITICAL(i_state);
}

os_time_t os_timer_get_interval(os_timer_t timer)
{
  timer_list_item_t *timer_item;
  timer_item = mlist_get(&g_timer_list.list, timer);
  return timer_item->interval;
}
